package com.nowcoder.topic.sort.middle;

import java.util.Stack;
import java.util.TreeSet;

/**
 * NC115 栈和排序
 * @author d3y1
 */
public class NC115{
    /**
     * 代码中的类名、方法名、参数名已经指定，请勿修改，直接返回方法规定的值即可
     *
     * 栈排序
     * @param a int整型一维数组 描述入栈顺序
     * @return int整型一维数组
     */
    public int[] solve (int[] a) {
        // return solution1(a);
        // return solution2(a);
        return solution3(a);
    }

    /**
     * 模拟法: Stack+TreeSet
     * @param a
     * @return
     */
    private int[] solution1(int[] a){
        int n = a.length;

        TreeSet<Integer> treeSet = new TreeSet<>((o1, o2) -> (o2-o1));
        for(int i=n-1; i>=0; i--){
            treeSet.add(a[i]);
            if(a[i] == n){
                break;
            }
        }

        int max = treeSet.pollFirst();

        int[] result = new int[n];
        Stack<Integer> stack = new Stack<>();
        int i = 0;
        for(int num: a){
            stack.push(num);
            treeSet.remove(num);
            if(stack.peek() == max){
                result[i++] = stack.pop();
                while(!stack.isEmpty() && !treeSet.isEmpty() && stack.peek()>treeSet.first()){
                    result[i++] = stack.pop();
                }
                if(!treeSet.isEmpty()){
                    max = treeSet.pollFirst();
                }
            }
        }

        while(!stack.isEmpty()){
            result[i++] = stack.pop();
        }

        return result;
    }

    /**
     * 模拟法: Stack(简化)
     * @param a
     * @return
     */
    private int[] solution2(int[] a){
        int n = a.length;
        // rMax[i]: i右侧最大值(不包括自身)
        int[] rMax = new int[n];
        int max = a[n-1];
        for(int i=n-2; i>=0; i--){
            max = Math.max(max, a[i+1]);
            rMax[i] = max;
        }

        int[] result = new int[n];
        Stack<Integer> stack = new Stack<>();
        for(int i=0,j=0; i<n; i++){
            stack.push(a[i]);
            if(stack.peek() == max){
                result[j++] = stack.pop();
                // rMax[n-1]=0 全部弹出
                while(!stack.isEmpty() && stack.peek()>rMax[i]){
                    result[j++] = stack.pop();
                }
                max = rMax[i];
            }
        }

        return result;
    }

    /**
     * 模拟法: Stack(再简化)
     * @param a
     * @return
     */
    private int[] solution3(int[] a){
        int n = a.length;
        // rMax[i]: i右侧最大值(包括自身)
        int[] rMax = new int[n];
        rMax[n-1] = a[n-1];
        for(int i=n-2; i>=0; i--){
            rMax[i] = Math.max(rMax[i+1], a[i]);
        }

        int[] result = new int[n];
        Stack<Integer> stack = new Stack<>();
        int j = 0;
        for(int i=0; i<n; i++){
            while(!stack.isEmpty() && stack.peek()>rMax[i]){
                result[j++] = stack.pop();
            }
            stack.push(a[i]);
        }

        while(!stack.isEmpty()){
            result[j++] = stack.pop();
        }

        return result;
    }
}